Reformat the pfn_info structure.
/* Relinquish Xen-heap pages. Currently this can only be 'shared_info'. */
page = virt_to_page(d->shared_info);
- if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
+ if ( test_and_clear_bit(_PGC_allocated, &page->u.inuse.count_info) )
put_page(page);
/* Relinquish all pages on the domain's allocation list. */
{
page = list_entry(ent, struct pfn_info, list);
- if ( test_and_clear_bit(_PGC_guest_pinned, &page->count_and_flags) )
+ if ( test_and_clear_bit(_PGC_guest_pinned, &page->u.inuse.count_info) )
put_page_and_type(page);
- if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
+ if ( test_and_clear_bit(_PGC_allocated, &page->u.inuse.count_info) )
put_page(page);
/*
* are not shared across domains and this domain is now dead. Thus base
* tables are not in use so a non-zero count means circular reference.
*/
- y = page->type_and_flags;
+ y = page->u.inuse.type_info;
do {
x = y;
if ( likely((x & (PGT_type_mask|PGT_validated)) !=
(PGT_base_page_table|PGT_validated)) )
break;
- y = cmpxchg(&page->type_and_flags, x, x & ~PGT_validated);
+ y = cmpxchg(&page->u.inuse.type_info, x, x & ~PGT_validated);
if ( likely(y == x) )
free_page_type(page, PGT_base_page_table);
}
mfn++ )
{
page = &frame_table[mfn];
- page->u.domain = p;
- page->type_and_flags = 0;
- page->count_and_flags = PGC_allocated | 1;
+ page->u.inuse.domain = p;
+ page->u.inuse.type_info = 0;
+ page->u.inuse.count_info = PGC_allocated | 1;
list_add_tail(&page->list, &p->page_list);
p->tot_pages++; p->max_pages++;
}
*l1tab++ = mk_l1_pgentry((mfn << PAGE_SHIFT) | L1_PROT);
page = &frame_table[mfn];
- set_bit(_PGC_tlb_flush_on_type_change, &page->count_and_flags);
+ set_bit(_PGC_tlb_flush_on_type_change, &page->u.inuse.count_info);
if ( !get_page_and_type(page, p, PGT_writeable_page) )
BUG();
page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
if ( count == 0 )
{
- page->type_and_flags &= ~PGT_type_mask;
- page->type_and_flags |= PGT_l2_page_table;
+ page->u.inuse.type_info &= ~PGT_type_mask;
+ page->u.inuse.type_info |= PGT_l2_page_table;
get_page(page, p); /* an extra ref because of readable mapping */
/* Get another ref to L2 page so that it can be pinned. */
if ( !get_page_and_type(page, p, PGT_l2_page_table) )
BUG();
- set_bit(_PGC_guest_pinned, &page->count_and_flags);
+ set_bit(_PGC_guest_pinned, &page->u.inuse.count_info);
}
else
{
- page->type_and_flags &= ~PGT_type_mask;
- page->type_and_flags |= PGT_l1_page_table;
+ page->u.inuse.type_info &= ~PGT_type_mask;
+ page->u.inuse.type_info |= PGT_l1_page_table;
get_page(page, p); /* an extra ref because of readable mapping */
}
l1tab++;
if ( unlikely(!get_page_type(page, type)) )
{
MEM_LOG("Bad page type for pfn %08lx (%08x)",
- page_nr, page->type_and_flags);
+ page_nr, page->u.inuse.type_info);
put_page(page);
return 0;
}
* If so, atomically increment the count (checking for overflow).
*/
page = &frame_table[l2_pgentry_to_pagenr(l2e)];
- y = page->type_and_flags;
+ y = page->u.inuse.type_info;
do {
x = y;
if ( unlikely((x & PGT_count_mask) == PGT_count_mask) ||
return 0;
}
}
- while ( (y = cmpxchg(&page->type_and_flags, x, x + 1)) != x );
+ while ( (y = cmpxchg(&page->u.inuse.type_info, x, x + 1)) != x );
}
return 1;
pfn, PGT_writeable_page, GPS)) )
return 0;
set_bit(_PGC_tlb_flush_on_type_change,
- &frame_table[pfn].count_and_flags);
+ &frame_table[pfn].u.inuse.count_info);
return 1;
}
else
{
/* We expect this is rare so we blow the entire shadow LDT. */
- if ( unlikely(((page->type_and_flags & PGT_type_mask) ==
+ if ( unlikely(((page->u.inuse.type_info & PGT_type_mask) ==
PGT_ldt_page)) &&
- unlikely(((page->type_and_flags & PGT_count_mask) != 0)) )
- invalidate_shadow_ldt(page->u.domain);
+ unlikely(((page->u.inuse.type_info & PGT_count_mask) != 0)) )
+ invalidate_shadow_ldt(page->u.inuse.domain);
put_page(page);
}
}
pl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
mk_l2_pgentry((page_nr << PAGE_SHIFT) | __PAGE_HYPERVISOR);
pl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(page->u.domain->mm.perdomain_pt) |
+ mk_l2_pgentry(__pa(page->u.inuse.domain->mm.perdomain_pt) |
__PAGE_HYPERVISOR);
#endif
int alloc_page_type(struct pfn_info *page, unsigned int type)
{
if ( unlikely(test_and_clear_bit(_PGC_tlb_flush_on_type_change,
- &page->count_and_flags)) )
+ &page->u.inuse.count_info)) )
{
- struct domain *p = page->u.domain;
+ struct domain *p = page->u.inuse.domain;
if ( unlikely(NEED_FLUSH(tlbflush_time[p->processor],
page->tlbflush_timestamp)) )
{
}
if ( unlikely(test_and_set_bit(_PGC_guest_pinned,
- &page->count_and_flags)) )
+ &page->u.inuse.count_info)) )
{
MEM_LOG("Pfn %08lx already pinned", pfn);
put_page_and_type(page);
if ( unlikely(!(okay = get_page_from_pagenr(pfn, PTS))) )
{
MEM_LOG("Page %08lx bad domain (dom=%p)",
- ptr, page->u.domain);
+ ptr, page->u.inuse.domain);
}
else if ( likely(test_and_clear_bit(_PGC_guest_pinned,
- &page->count_and_flags)) )
+ &page->u.inuse.count_info)) )
{
put_page_and_type(page);
put_page(page);
* benign reference to the page (PGC_allocated). If that reference
* disappears then the deallocation routine will safely spin.
*/
- nd = page->u.domain;
- y = page->count_and_flags;
+ nd = page->u.inuse.domain;
+ y = page->u.inuse.count_info;
do {
x = y;
if ( unlikely((x & (PGC_count_mask|PGC_allocated)) !=
{
MEM_LOG("Bad page values %08lx: ed=%p(%u), sd=%p,"
" caf=%08x, taf=%08x\n", page_to_pfn(page),
- d, d->domain, nd, x, page->type_and_flags);
+ d, d->domain, nd, x, page->u.inuse.type_info);
okay = 0;
goto reassign_fail;
}
__asm__ __volatile__(
LOCK_PREFIX "cmpxchg8b %3"
: "=a" (nd), "=d" (y), "=b" (e),
- "=m" (*(volatile u64 *)(&page->u.domain))
+ "=m" (*(volatile u64 *)(&page->u.inuse.domain))
: "0" (d), "1" (x), "b" (e), "c" (x) );
}
while ( unlikely(nd != d) || unlikely(y != x) );
}
page = &frame_table[pfn];
- switch ( (page->type_and_flags & PGT_type_mask) )
+ switch ( (page->u.inuse.type_info & PGT_type_mask) )
{
case PGT_l1_page_table:
if ( likely(get_page_type(page, PGT_l1_page_table)) )
struct pfn_info *pfn_info )
{
unsigned long flags;
- unsigned long type = pfn_info->type_and_flags & PGT_type_mask;
+ unsigned long type = pfn_info->u.inuse.type_info & PGT_type_mask;
m->shadow_page_count--;
else if (type == PGT_l2_page_table)
perfc_decr(shadow_l2_pages);
else printk("Free shadow weird page type pfn=%08x type=%08x\n",
- frame_table-pfn_info, pfn_info->type_and_flags);
+ frame_table-pfn_info, pfn_info->u.inuse.type_info);
- pfn_info->type_and_flags = 0;
+ pfn_info->u.inuse.type_info = 0;
spin_lock_irqsave(&free_list_lock, flags);
list_add(&pfn_info->list, &free_list);
{
case TABLE_OP_ZERO_L2:
{
- if ( (spfn_info->type_and_flags & PGT_type_mask) ==
+ if ( (spfn_info->u.inuse.type_info & PGT_type_mask) ==
PGT_l2_page_table )
{
unsigned long * spl1e = map_domain_mem( spfn<<PAGE_SHIFT );
case TABLE_OP_ZERO_L1:
{
- if ( (spfn_info->type_and_flags & PGT_type_mask) ==
+ if ( (spfn_info->u.inuse.type_info & PGT_type_mask) ==
PGT_l1_page_table )
{
unsigned long * spl1e = map_domain_mem( spfn<<PAGE_SHIFT );
case TABLE_OP_FREE_L1:
{
- if ( (spfn_info->type_and_flags & PGT_type_mask) ==
+ if ( (spfn_info->u.inuse.type_info & PGT_type_mask) ==
PGT_l1_page_table )
{
// lock is already held
ASSERT( spfn_info ); // XXX deal with failure later e.g. blow cache
- spfn_info->type_and_flags = PGT_l2_page_table;
+ spfn_info->u.inuse.type_info = PGT_l2_page_table;
perfc_incr(shadow_l2_pages);
spfn = (unsigned long) (spfn_info - frame_table);
spl2e[SH_LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
mk_l2_pgentry((spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(frame_table[gpfn].u.domain->mm.perdomain_pt) |
+ mk_l2_pgentry(__pa(frame_table[gpfn].u.inuse.domain->mm.perdomain_pt) |
__PAGE_HYPERVISOR);
#endif
unsigned long *gpl1e, *spl1e;
int i;
sl1pfn_info = alloc_shadow_page( ¤t->mm );
- sl1pfn_info->type_and_flags = PGT_l1_page_table;
+ sl1pfn_info->u.inuse.type_info = PGT_l1_page_table;
sl1pfn = sl1pfn_info - frame_table;
);
if ( (l2_pgentry_val(spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT]) !=
- ((__pa(frame_table[gpfn].u.domain->mm.perdomain_pt) | __PAGE_HYPERVISOR))) )
+ ((__pa(frame_table[gpfn].u.inuse.domain->mm.perdomain_pt) | __PAGE_HYPERVISOR))) )
FAILPT("hypervisor per-domain map inconsistent");
return -EINVAL;
/* Check if the given frame is in use in an unsafe context. */
- switch ( page->type_and_flags & PGT_type_mask )
+ switch ( page->u.inuse.type_info & PGT_type_mask )
{
case PGT_gdt_page:
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
op->u.getpageframeinfo.type = NOTAB;
- if ( (page->type_and_flags & PGT_count_mask) != 0 )
+ if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
{
- switch ( page->type_and_flags & PGT_type_mask )
+ switch ( page->u.inuse.type_info & PGT_type_mask )
{
case PGT_l1_page_table:
op->u.getpageframeinfo.type = L1TAB;
if ( likely(get_page(page, d)) )
{
unsigned long type = 0;
- switch( page->type_and_flags & PGT_type_mask )
+ switch( page->u.inuse.type_info & PGT_type_mask )
{
case PGT_l1_page_table:
type = L1TAB;
break;
}
- if ( test_and_clear_bit(_PGC_guest_pinned, &page->count_and_flags) )
+ if ( test_and_clear_bit(_PGC_guest_pinned, &page->u.inuse.count_info) )
put_page_and_type(page);
- if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
+ if ( test_and_clear_bit(_PGC_allocated, &page->u.inuse.count_info) )
put_page(page);
put_page(page);
if ( unlikely(page == NULL) )
return NULL;
- if ( (mask = page->u.cpu_mask) != 0 )
+ if ( (mask = page->u.free.cpu_mask) != 0 )
{
pfn_stamp = page->tlbflush_timestamp;
for ( i = 0; (mask != 0) && (i < smp_num_cpus); i++ )
}
}
- page->u.domain = d;
- page->type_and_flags = 0;
+ page->u.inuse.domain = d;
+ page->u.inuse.type_info = 0;
if ( d != NULL )
{
wmb(); /* Domain pointer must be visible before updating refcnt. */
goto free_and_exit;
}
list_add_tail(&page->list, &d->page_list);
- page->count_and_flags = PGC_allocated | 1;
+ page->u.inuse.count_info = PGC_allocated | 1;
if ( unlikely(d->tot_pages++ == 0) )
get_domain(d);
spin_unlock(&d->page_alloc_lock);
{
unsigned long flags;
int drop_dom_ref;
- struct domain *d = page->u.domain;
+ struct domain *d = page->u.inuse.domain;
if ( unlikely(IS_XEN_HEAP_FRAME(page)) )
{
else
{
page->tlbflush_timestamp = tlbflush_clock;
- page->u.cpu_mask = 1 << d->processor;
+ page->u.free.cpu_mask = 1 << d->processor;
/* NB. May recursively lock from domain_relinquish_memory(). */
spin_lock_recursive(&d->page_alloc_lock);
drop_dom_ref = (--d->tot_pages == 0);
spin_unlock_recursive(&d->page_alloc_lock);
- page->count_and_flags = 0;
+ page->u.inuse.count_info = 0;
spin_lock_irqsave(&free_list_lock, flags);
list_add(&page->list, &free_list);
{
page = list_entry(ent, struct pfn_info, list);
printk("Page %08x: caf=%08x, taf=%08x\n",
- page_to_phys(page), page->count_and_flags,
- page->type_and_flags);
+ page_to_phys(page), page->u.inuse.count_info,
+ page->u.inuse.type_info);
}
}
page = virt_to_page(d->shared_info);
printk("Shared_info@%08x: caf=%08x, taf=%08x\n",
- page_to_phys(page), page->count_and_flags,
- page->type_and_flags);
+ page_to_phys(page), page->u.inuse.count_info,
+ page->u.inuse.type_info);
printk("Guest: upcall_pend = %02x, upcall_mask = %02x\n",
d->shared_info->vcpu_data[0].evtchn_upcall_pending,
mfn < virt_to_phys(&machine_to_phys_mapping[1<<20])>>PAGE_SHIFT;
mfn++ )
{
- frame_table[mfn].count_and_flags = 1 | PGC_allocated;
- frame_table[mfn].type_and_flags = 1 | PGT_gdt_page; /* non-RW type */
- frame_table[mfn].u.domain = &idle0_task;
+ frame_table[mfn].u.inuse.count_info = 1 | PGC_allocated;
+ frame_table[mfn].u.inuse.type_info = 1 | PGT_gdt_page; /* non-RW type */
+ frame_table[mfn].u.inuse.domain = &idle0_task;
}
}
/*
* Per-page-frame information.
+ *
+ * Every architecture must ensure the following:
+ * 1. 'struct pfn_info' contains a 'struct list_head list'.
+ * 2. Provide a PFN_ORDER() macro for accessing the order of a free page.
*/
+#define PFN_ORDER(_pfn) ((_pfn)->u.free.order)
struct pfn_info
{
/* Each frame can be threaded onto a doubly-linked list. */
struct list_head list;
- /* The following possible uses are context-dependent. */
+
+ /* Context-dependent fields follow... */
union {
- /* Page is in use: we keep a pointer to its owner. */
- struct domain *domain;
- /* Page is not currently allocated: mask of possibly-tainted TLBs. */
- unsigned long cpu_mask;
+
+ /* Page is in use by a domain. */
+ struct {
+ /* Owner of this page. */
+ struct domain *domain;
+ /* Reference count and various PGC_xxx flags and fields. */
+ u32 count_info;
+ /* Type reference count and various PGT_xxx flags and fields. */
+ u32 type_info;
+ } inuse;
+
+ /* Page is on a free list. */
+ struct {
+ /* Mask of possibly-tainted TLBs. */
+ unsigned long cpu_mask;
+ /* Must be at same offset as 'u.inuse.count_flags'. */
+ u32 __unavailable;
+ /* Order-size of the free chunk this page is the head of. */
+ u8 order;
+ } free;
+
} u;
- /* Reference count and various PGC_xxx flags and fields. */
- u32 count_and_flags;
- /* Type reference count and various PGT_xxx flags and fields. */
- u32 type_and_flags;
+
/* Timestamp from 'TLB clock', used to reduce need for safety flushes. */
u32 tlbflush_timestamp;
};
#define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \
do { \
- (_pfn)->u.domain = (_dom); \
+ (_pfn)->u.inuse.domain = (_dom); \
/* The incremented type count is intended to pin to 'writeable'. */ \
- (_pfn)->type_and_flags = PGT_writeable_page | PGT_validated | 1; \
+ (_pfn)->u.inuse.type_info = PGT_writeable_page | PGT_validated | 1; \
wmb(); /* install valid domain ptr before updating refcnt. */ \
spin_lock(&(_dom)->page_alloc_lock); \
/* _dom holds an allocation reference */ \
- (_pfn)->count_and_flags = PGC_allocated | 1; \
+ (_pfn)->u.inuse.count_info = PGC_allocated | 1; \
if ( unlikely((_dom)->xenheap_pages++ == 0) ) \
get_domain(_dom); \
spin_unlock(&(_dom)->page_alloc_lock); \
static inline void put_page(struct pfn_info *page)
{
- u32 nx, x, y = page->count_and_flags;
+ u32 nx, x, y = page->u.inuse.count_info;
do {
x = y;
nx = x - 1;
}
- while ( unlikely((y = cmpxchg(&page->count_and_flags, x, nx)) != x) );
+ while ( unlikely((y = cmpxchg(&page->u.inuse.count_info, x, nx)) != x) );
if ( unlikely((nx & PGC_count_mask) == 0) )
free_domain_page(page);
static inline int get_page(struct pfn_info *page,
struct domain *domain)
{
- u32 x, nx, y = page->count_and_flags;
- struct domain *p, *np = page->u.domain;
+ u32 x, nx, y = page->u.inuse.count_info;
+ struct domain *p, *np = page->u.inuse.domain;
do {
x = y;
" caf=%08x, taf=%08x\n",
page_to_pfn(page), domain, domain->domain,
p, (p && !((x & PGC_count_mask) == 0))?p->domain:999,
- x, page->type_and_flags);
+ x, page->u.inuse.type_info);
return 0;
}
__asm__ __volatile__(
LOCK_PREFIX "cmpxchg8b %3"
: "=a" (np), "=d" (y), "=b" (p),
- "=m" (*(volatile u64 *)(&page->u.domain))
+ "=m" (*(volatile u64 *)(&page->u.inuse.domain))
: "0" (p), "1" (x), "b" (p), "c" (nx) );
}
while ( unlikely(np != p) || unlikely(y != x) );
static inline void put_page_type(struct pfn_info *page)
{
- u32 nx, x, y = page->type_and_flags;
+ u32 nx, x, y = page->u.inuse.type_info;
again:
do {
* 'free' is safe because the refcnt is non-zero and the
* validated bit is clear => other ops will spin or fail.
*/
- if ( unlikely((y = cmpxchg(&page->type_and_flags, x,
+ if ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x,
x & ~PGT_validated)) != x) )
goto again;
/* We cleared the 'valid bit' so we must do the clear up. */
}
}
}
- while ( unlikely((y = cmpxchg(&page->type_and_flags, x, nx)) != x) );
+ while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
}
static inline int get_page_type(struct pfn_info *page, u32 type)
{
- u32 nx, x, y = page->type_and_flags;
+ u32 nx, x, y = page->u.inuse.type_info;
again:
do {
x = y;
else if ( unlikely(!(x & PGT_validated)) )
{
/* Someone else is updating validation of this page. Wait... */
- while ( (y = page->type_and_flags) != x )
+ while ( (y = page->u.inuse.type_info) != x )
{
rep_nop();
barrier();
goto again;
}
}
- while ( unlikely((y = cmpxchg(&page->type_and_flags, x, nx)) != x) );
+ while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
if ( unlikely(!(nx & PGT_validated)) )
{
put_page_type(page);
return 0;
}
- set_bit(_PGT_validated, &page->type_and_flags);
+ set_bit(_PGT_validated, &page->u.inuse.type_info);
}
return 1;
}
#define ASSERT_PAGE_IS_TYPE(_p, _t) \
- ASSERT(((_p)->type_and_flags & PGT_type_mask) == (_t)); \
- ASSERT(((_p)->type_and_flags & PGT_count_mask) != 0)
+ ASSERT(((_p)->u.inuse.type_info & PGT_type_mask) == (_t)); \
+ ASSERT(((_p)->u.inuse.type_info & PGT_count_mask) != 0)
#define ASSERT_PAGE_IS_DOMAIN(_p, _d) \
- ASSERT(((_p)->count_and_flags & PGC_count_mask) != 0); \
- ASSERT((_p)->u.domain == (_d))
+ ASSERT(((_p)->u.inuse.count_info & PGC_count_mask) != 0); \
+ ASSERT((_p)->u.inuse.domain == (_d))
int check_descriptor(unsigned long *d);
SH_LOG("mark_dirty OOR! mfn=%x pfn=%x max=%x (mm %p)",
mfn, pfn, m->shadow_dirty_bitmap_size, m );
SH_LOG("dom=%u caf=%08x taf=%08x\n",
- frame_table[mfn].u.domain->domain,
- frame_table[mfn].count_and_flags,
- frame_table[mfn].type_and_flags );
+ frame_table[mfn].u.inuse.domain->domain,
+ frame_table[mfn].u.inuse.count_info,
+ frame_table[mfn].u.inuse.type_info );
}
return rc;